
#pragma once
#include "net.hpp"
#include "abstract.hpp"
#include "message.hpp"
/*
dipatcher负责消息类型与业务处理之间的映射，请求和响应都是多样化的，服务端和客户端都会收到不同的请求和响应，
所以在消息处理的回调函数中，需要判断消息类型，根据不同类型的消息做出不同的处理，如果单纯用if语句分支非常不好，
程序设计要遵循开闭原则：对修改关闭，对扩展开放；
当后期维护代码或新增功能时，不去修改以前的代码，而是新增当前需要的代码，如果后期需要新增一个业务处理，只需要添加一个映射关系即可
*/
namespace bitrpc
{
    class CallBack
    {
      public:
         using ptr = std::shared_ptr<CallBack>;
        virtual void onMessage(const BaseConnection::ptr & conn,BaseMessage::ptr & msg) = 0;
         
    };
    template<class T>
    class CallBackT : public CallBack
    {
       public:
        using ptr = std::shared_ptr<CallBackT<T>>;
        using MessageCallback = std::function<void(const BaseConnection::ptr &,std::shared_ptr<T>&)>;
        CallBackT(const MessageCallback& handler):_handler(handler){

        }
       void onMessage(const BaseConnection::ptr & conn,BaseMessage::ptr & msg) override
        {
            auto type_msg = std::dynamic_pointer_cast<T>(msg);//将父类转换为子类
            _handler(conn,type_msg);
        }

       private:
         MessageCallback _handler;
    };
    class dispatcher
    {
        public:
         using ptr = std::shared_ptr<dispatcher>;

          //注册映射关系
          //服务端知道自己要处理哪种请求，比如RPCRequest，如果被注册方法的第二参数是BaseMessage,那么很多
          //子类的方法都无法使用，所以为了上层处理方便，dispatcher应该能注册各种请求的回调方法
          //又因为不同请求的回调方法类型不同，不符合哈希表要求，所以用统一的类来存储不同类型的回调方法
          template<class T>
          void registerHandler(MessageType mtype,const typename CallBackT<T>::MessageCallback& handler)
          {
            std::unique_lock<std::mutex>lock(mutex);
           CallBack::ptr  cb = std::make_shared<CallBackT<T>>(handler);
             
            _handlers[mtype] = cb;
          }
          //根据消息类型转发业务处理,应将此方法注册给服务端或客户端的消息处理回调函数中
          void onMessage(const BaseConnection::ptr & conn,BaseMessage::ptr& msg)
          {
            DLOG("dispatcher收到消息");
            //找到消息类型对应业务处理函数，进行调用即可
            std::unique_lock<std::mutex>lock(mutex);
            if(_handlers.count(msg->messageType()))
            {
            DLOG("dispatcher找到了回调函数,消息类型：%d",(int)msg->messageType());

                _handlers[msg->messageType()]->onMessage(conn,msg);
            }
            else{
                ELOG("收到未知类型的消息");
                conn->shutdown();
            }
          }
        private:
        std::mutex _mutex;
        std::unordered_map<MessageType,CallBack::ptr> _handlers;
    };
}